﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using Fiddler;
using Newtonsoft.Json.Linq;

namespace BareWeb.BuiltWithFiddler.Helper
{
    /// <summary>
    /// Provides helper methods for accessing BuiltWith data, checking licensing info and other details
    /// </summary>
    public class BuiltWithHelper
    {
        private const string BUILTWITHFORMAT = "http://api.builtwith.com/api.json?KEY={0}&LOOKUP={1}&CACHE={2}";
        private const string BUILTWITHKEYPREF = "bareweb.builtwith.ownkey";

        internal const string BUILTWITHFREEHITSPREF = "bareweb.builtwith.freehits.count";
        private const string BUILTWITHFREEHITSMONTHSTAMPPREF = "bareweb.builtwith.freehits.monthstamp";
        private const int BUILTWITHMAXFREEHITS = 100;

        public const string OPENLICENCEKEY = "832F00D4-1EE2-4076-AC07-F0BFC61B238D";

        public bool CanMakeHttpRequests { get; set; }

        private WebClient _client;
        public BuiltWithHelper(): this(true)
        {
            
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BuiltWithHelper"/> class.
        /// </summary>
        /// <param name="enableHttp">if set to <c>true</c> will create a class able to communicate over http.</param>
        public BuiltWithHelper(bool enableHttp)
        {
            CanMakeHttpRequests = enableHttp;

            if (CanMakeHttpRequests)
                _client = new WebClient();
        }

        /// <summary>
        /// Gets the json from builtwith.com .
        /// </summary>
        /// <param name="lookup">The lookup.</param>
        /// <param name="supportCache">if set to <c>true</c> [support cache].</param>
        /// <returns></returns>
        public JObject GetJsonFromBuiltWith(string lookup, bool supportCache)
        {
            var key = GetKey();

            if (!CanMakeHttpRequests)
            {
                throw new InvalidOperationException("The WebClient was not ready. Instantiate this class with the true contructor value or parameterless constructor.");    
            }

            if (key.Equals(OPENLICENCEKEY))
            {
                int executedValues = FiddlerApplication.Prefs.GetInt32Pref(BUILTWITHFREEHITSPREF, 0);
                int executionTimeStamp = FiddlerApplication.Prefs.GetInt32Pref(BUILTWITHFREEHITSMONTHSTAMPPREF,
                                                                               DateTime.Now.Month);

                //reset the requests should the month have rolled over
                if (executionTimeStamp != DateTime.Now.Month)
                {
                    executedValues = 0;
                }
                FiddlerApplication.Prefs.SetInt32Pref(BUILTWITHFREEHITSMONTHSTAMPPREF, DateTime.Now.Month);

                if (executedValues > BUILTWITHMAXFREEHITS)
                {
                    throw new ApplicationException(
                        string.Format(
                            "The unlicenced version of BuiltWith allows for 100 free requests per month. BuiltWith is not a free product and should not be used commercially without obtaining a licence. This Fiddler Extension offered by Bare Web integrates at their pleasure, so please consider an upgrade or contact andy@bareweb.eu for advice. You have issued {0} requests this month.",
                            executedValues));
                }
                FiddlerApplication.Prefs.SetInt32Pref(BUILTWITHFREEHITSPREF, executedValues + 1);
            }

            string formattedUri = HttpUtility.UrlEncode(lookup);
            var rawData = _client.DownloadString(string.Format(BUILTWITHFORMAT, key, formattedUri, supportCache));

            // the Error messages returned by BuiltWith contain Xml so must not be passed through to JObject [unless you want a bang]
            if (rawData.Contains("<Error>"))
            {
                FiddlerApplication.Log.LogFormat("An error occurred when communicating with BuiltWith. {0}", rawData);

                throw new ApplicationException(
                    "An error occurred when communicating with BuiltWith. See Log for more info.");
            }
            return JObject.Parse(rawData);

        }

        /// <summary>
        /// Gets the key.
        /// </summary>
        /// <returns></returns>
        public string GetKey()
        {
            var configKey = FiddlerApplication.Prefs.GetStringPref(BUILTWITHKEYPREF, string.Empty);
            if (string.IsNullOrEmpty(configKey))
            {
                return OPENLICENCEKEY;
            }
            return configKey;
        }


        /// <summary>
        /// Sets the key.
        /// </summary>
        /// <param name="keyValue">The key value.</param>
        internal void SetKey(string keyValue)
        {
            FiddlerApplication.Prefs.SetStringPref(BUILTWITHKEYPREF, keyValue);
        }

        /// <summary>
        /// Determines whether [is excluded tag] [the specified tag name].
        /// </summary>
        /// <param name="tagName">Name of the tag.</param>
        /// <returns>
        /// 	<c>true</c> if [is excluded tag] [the specified tag name]; otherwise, <c>false</c>.
        /// </returns>
        internal bool IsExcludedTag(string tagName)
        {
            return tagName.ToLower().StartsWith("seo_");
        }
    }
}
